/**     
 * @Title: MyHandlerMethodArgumentResolver.java   
 * @Package com.yitong.spring.resolver   
 * @Description: TODO
 * @author weiwei 
 * @date 2017年7月21日 上午10:19:23   
 * @version V1.0     
 */
package com.yitong.spring.resolver;

import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.MethodParameter;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.yitong.spring.annotation.ReqJson;
import com.yitong.spring.reqcheck.exception.CheckException;
import com.yitong.spring.reqcheck.exception.DataTypesException;
import com.yitong.utils.ConstantUtils;

/**
 * @ClassName: MyHandlerMethodArgumentResolver
 * @Description: TODO
 * @author weiwei
 * @date 2017年7月21日 上午10:19:23
 * 
 */
@Component
public class MyHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {

	private static final Logger LOGGER = LoggerFactory.getLogger(MyHandlerMethodArgumentResolver.class);

	private static final String PARAMETER_EMPTY_ERR = "参数为空";

	private static final String PARAMETER_TYPE_ERR = "数据类型不正确，应为";

	@Override
	public boolean supportsParameter(MethodParameter parameter) {
		if (parameter.hasParameterAnnotation(ReqJson.class)) {
			return true;
		}
		return false;
	}

	@Override
	public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
		ReqJson reqJson = parameter.getParameterAnnotation(ReqJson.class);
		if (parameter.getParameterType().isAssignableFrom(JSON.class)) {
			return webRequest.getAttribute(ConstantUtils.INTER_PARAMTER, RequestAttributes.SCOPE_REQUEST);
		} else {
			Object obj = webRequest.getAttribute(ConstantUtils.INTER_PARAMTER, RequestAttributes.SCOPE_REQUEST);
			if (null != obj && !(obj instanceof JSON)) {
				throw new JSONException("请求数据格式不正确");
			}
			JSON json = (JSON) obj;
			String name = reqJson.name();
			if (StringUtils.isEmpty(name)) {
				name = parameter.getParameterName();
			}
			boolean required = reqJson.required();
			try {
				if (json instanceof JSONObject) {
					JSONObject jsonObject = (JSONObject) json;
					if (parameter.getParameterType().isAssignableFrom(String.class)) {
						String val = null;
						try {
							val = jsonObject.getString(name);
						} catch (Exception e) {
							LOGGER.error(e.getMessage(), e);
							throw new DataTypesException(name + PARAMETER_TYPE_ERR + "String", name);
						}
						if (StringUtils.isBlank(val) && required) {
							throw new CheckException(name + PARAMETER_EMPTY_ERR, name);
						}
						return val;
					} else if (parameter.getParameterType().isAssignableFrom(Integer.class)) {
						Integer val = null;
						try {
							val = jsonObject.getInteger(name);
						} catch (Exception e) {
							LOGGER.error(e.getMessage(), e);
							throw new DataTypesException(name + PARAMETER_TYPE_ERR + "Integer", name);
						}
						if (required && null == val) {
							throw new CheckException(name + PARAMETER_EMPTY_ERR, name);
						}
						return val;
					} else if (parameter.getParameterType().isAssignableFrom(Long.class)) {
						Long val = null;
						try {
							val = jsonObject.getLong(name);
						} catch (Exception e) {
							LOGGER.error(e.getMessage(), e);
							throw new DataTypesException(name + PARAMETER_TYPE_ERR + "Long", name);
						}
						if (required && null == val) {
							throw new CheckException(name + PARAMETER_EMPTY_ERR, name);
						}
						return val;
					} else if (parameter.getParameterType().isAssignableFrom(Double.class)) {
						Double val = null;
						try {
							val = jsonObject.getDouble(name);
						} catch (Exception e) {
							LOGGER.error(e.getMessage(), e);
							throw new DataTypesException(name + PARAMETER_TYPE_ERR + "Double", name);
						}
						if (required && null == val) {
							throw new CheckException(name + PARAMETER_EMPTY_ERR, name);
						}
						return val;
					} else if (parameter.getParameterType().isAssignableFrom(Float.class)) {
						Float val = null;
						try {
							val = jsonObject.getFloat(name);
						} catch (Exception e) {
							LOGGER.error(e.getMessage(), e);
							throw new DataTypesException(name + PARAMETER_TYPE_ERR + "Float", name);
						}
						if (required && null == val) {
							throw new CheckException(name + PARAMETER_EMPTY_ERR, name);
						}
						return val;
					} else if (parameter.getParameterType().isAssignableFrom(Boolean.class)) {
						Boolean val = null;
						try {
							val = jsonObject.getBoolean(name);
						} catch (Exception e) {
							LOGGER.error(e.getMessage(), e);
							throw new DataTypesException(name + PARAMETER_TYPE_ERR + "Boolean", name);
						}
						if (required && null == val) {
							throw new CheckException(name + PARAMETER_EMPTY_ERR, name);
						}
						return val;
					} else if (parameter.getParameterType().isArray()) {
						JSONArray array = null;
						try {
							array = jsonObject.getJSONArray(name);
						} catch (Exception e) {
							LOGGER.error(e.getMessage(), e);
							throw new DataTypesException(name + PARAMETER_TYPE_ERR + "Array", name);
						}
						if (required && (null == array || array.isEmpty())) {
							throw new CheckException(name + " " + PARAMETER_EMPTY_ERR, name);
						}
						return JSON.parseArray(array.toJSONString(), parameter.getParameterType().getClasses()).toArray();
					} else if (parameter.getParameterType().isAssignableFrom(List.class)) {
						JSONArray array = null;
						try {
							array = jsonObject.getJSONArray(name);
						} catch (Exception e) {
							LOGGER.error(e.getMessage(), e);
							throw new DataTypesException(name + PARAMETER_TYPE_ERR + "Array", name);
						}
						if (required && (null == array || array.isEmpty())) {
							throw new CheckException(name + PARAMETER_EMPTY_ERR, name);
						}
						return array;
					} else {
						try {
							return JSON.parseObject(json.toJSONString(), parameter.getParameterType());
						} catch (JSONException e) {
							LOGGER.error(e.getMessage(), e);
							throw new JSONException("请求数据格式不正确");
						}
					}
				} else {
					try {
						JSONArray array = (JSONArray) json;
						return JSONArray.toJavaObject(array, parameter.getParameterType());
					} catch (Exception e) {
						LOGGER.error(e.getMessage(), e);
						throw new DataTypesException(name + PARAMETER_TYPE_ERR + "Array", name);
					}
				}
			} catch (JSONException e) {
				LOGGER.error(e.getMessage(), e);
				throw new JSONException("请求数据格式不正确");
			}
		}
	}

}
